#include <stdlib.h>
#include <stdio.h>
#include "tables.h"
//using namespace std;

typedef enum
{
    false = 0,
    true = 1
} bool;

static bool SubKey[16][48] = {0};

//二进制串复制
void BitsCopy(bool *BitStringB, bool *BitStringA, int len);

//字节与二进制串之间的转化
void ByteToBit(bool *BitString, char *String, int Num);
void BitToByte(char *String, bool *BitString, int Num);

//16进制串与二进制串之间的转化
void BitToHex(char *HexString, bool *BitString, int num);
void HexToBit(bool *BitString, char *HexString, int num);

//左移
void LeftShift(bool *BINString, int len, int num);
//生成子密钥
void GenerateSubKey(char Key[64]);
//根据表置换
void TablePermute(bool *output, bool *input, const char *table, int Num);
//按位异或
void XOR(bool *a, bool *b, int num);
//S盒选择
void SBoxSelect(bool output[32], bool intput[48]);
//Feistel轮函数，生成L16R16
void Feistel(bool t_R[32], bool t_Subkey[48]);

//加密与解密流程
void Encryption(char ciphertext[8], char plaintext[8]);
void Decryption(char plaintext[8], char ciphertext[8]);

// 加密大长度内容
char *EncryptionBS(char *bigSizeText, char *key);
char *DecryptionBS(char *bigSizeText, char *key);

// int main()
// {
//     int i = 0;
//     char MesHex[16] = {0};
//     char MyKey[8] = {0};
//     char YourKey[8] = {0};
//     char MyMessage[8] = {0};

//     printf("-----------------DES Demo-----------------\n");
//     printf("Please input the content you want to encrypt\n");
//     gets(MyMessage);
//     printf("Please input your Secret Key:\n");
//     gets(MyKey);

//     for (i = 0; i < 8; i++)
//     {
//         printf("%c", MyMessage[i]);
//     }
//     printf("\n");
//     while (MyKey[i] != '\0')
//     {
//         i++;
//     }
//     while (i != 8)
//     {
//         printf("Please input a correct Secret Key (8-bits)\n");
//         gets(MyKey);
//         i = 0;
//         while (MyKey[i] != '\0')
//         {
//             i++;
//         }
//     }

//     GenerateSubKey(MyKey);
//     encryption(MesHex, MyMessage);

//     printf("Your Message is Encrypted!:\n");
//     for (i = 0; i < 16; i++)
//     {
//         printf("%c ", MesHex[i]);
//     }
//     printf("\n");
//     printf("\n");

//     printf("Please input your Secret Key to Deciphering:\n");
//     gets(YourKey);
//     GenerateSubKey(YourKey);

//     Decryption(MyMessage, MesHex);

//     printf("Deciphering Over !!:\n");
//     for (i = 0; i < 8; i++)
//     {
//         printf("%c ", MyMessage[i]);
//     }
//     printf("\n");
//     system("pause");
// }

void BitsCopy(bool *BitStringB, bool *BitStringA, int len)
{
    int i;
    for (i = 0; i < len; i++)
    {
        BitStringB[i] = BitStringA[i];
    }
}

void ByteToBit(bool *BitString, char *String, int Num)
{
    int i;
    for (i = 0; i < Num; i++)
    {
        BitString[i] = (String[i / 8] >> (i % 8)) & 0x01;
    }
}

void BitToByte(char *String, bool *BitString, int Num)
{
    int i;
    for (i = 0; i < Num / 8; i++)
    {
        String[i] = 0;
    }
    for (i = 0; i < Num; i++)
    {
        int index = i / 8;
        String[index] |= BitString[i] << (i % 8);
    }
}

void BitToHex(char *HexString, bool *BitString, int num)
{
    int i;
    for (i = 0; i < num / 4; i++)
    {
        HexString[i] = 0;
    }
    for (i = 0; i < num / 4; i++)
    {
        HexString[i] = BitString[i * 4] + (BitString[i * 4 + 1] << 1) +
                       (BitString[i * 4 + 2] << 2) + (BitString[i * 4 + 3] << 3);
        if (HexString[i] % 16 > 9)
        {
            HexString[i] = HexString[i] % 16 + '7';
        }
        else
        {
            HexString[i] = HexString[i] % 16 + '0';
        }
    }
}

void HexToBit(bool *BitString, char *HexString, int num)
{
    int i;
    for (i = 0; i < num; i++)
    {
        if (HexString[i / 4] > '9')
        {
            BitString[i] = (HexString[i / 4] - '7') >> (i % 4) & 0x01;
        }
        else
        {
            BitString[i] = (HexString[i / 4] - '0') >> (i % 4) & 0x01;
        }
    }
}

void LeftShift(bool *BINString, int len, int num)
{
    static bool temp[256] = {0};
    //将左移后的二进制串更新
    BitsCopy(BINString, BINString + num, len - num);
    //将被左移位的值设为0
    BitsCopy(BINString + len - num, temp, num);
}

/*
    根据给定的64位密钥 K，生成16个48位的子密钥 K1 - K16，
    供Feistel 轮函数 f(Ri-1, Ki) 调用。
*/
void GenerateSubKey(char Key[8])
{
    static bool KeyBit[64] = {0};
    static bool *Ci = &KeyBit[0];
    static bool *Di = &KeyBit[28];
    //0.将密钥转成二进制串
    ByteToBit(KeyBit, Key, 64);
    //1.对二进制进行PC-1置换
    TablePermute(KeyBit, KeyBit, PC1_table, 56);
    int i;
    for (i = 0; i < 16; i++)
    {
        //2.计算Ci和Di
        LeftShift(Ci, 28, Move_table[i]);
        LeftShift(Di, 28, Move_table[i]);
        //3.对56位的 CiDi压缩后实行 PC-2 置换，得到48位的 Ki
        TablePermute(SubKey[i], KeyBit, PC2_table, 48);
    }
}

void TablePermute(bool *output, bool *input, const char *table, int num)
{
    int i;
    static bool temp[256] = {0};
    for (i = 0; i < num; i++)
    {
        temp[i] = input[table[i] - 1];
    }
    BitsCopy(output, temp, num);
}

void XOR(bool *a, bool *b, int num)
{
    int i;
    for (i = 0; i < num; i++)
    {
        a[i] = a[i] ^ b[i];
    }
}

void SBoxSelect(bool output[32], bool intput[48])
{
    int i = 0, n, m;
    while (i < 8)
    {
        //n为行号，m为列号
        n = (intput[0] << 1) + intput[5];
        m = (intput[1] << 3) + (intput[2] << 2) + (intput[3] << 1) + intput[4];
        ByteToBit(output, &S_Box[i][n][m], 4);
        intput += 6;
        output += 4;
        i++;
    }
}

void Feistel(bool t_R[32], bool t_Subkey[48])
{
    static bool ER[48] = {0};
    //1. E-扩展
    TablePermute(ER, t_R, E_table, 48);
    //2. 将ER与子密钥按位异或运算
    XOR(ER, t_Subkey, 48);
    //3. ER经过S-Box进行6-4变换，并将结果连接为32位的串
    SBoxSelect(t_R, ER);
    //4. 将3的结果进行P-置换
    TablePermute(t_R, t_R, P_table, 32);
}

void Encryption(char ciphertext[8], char plaintext[8])
{
    static bool plaBit[64] = {0};
    static bool temp[32] = {0};
    static bool *Li = &plaBit[0];
    static bool *Ri = &plaBit[32];
    int i;
    //0. 明文转二进制串
    ByteToBit(plaBit, plaintext, 64);
    int j = 0;
    //1. 初识置换IP
    TablePermute(plaBit, plaBit, IP_table, 64);
    //2. 16轮迭代T
    for (i = 0; i < 16; i++)
    {
        //将Ri-1复制到temp
        BitsCopy(temp, Ri, 32);
        //2.1 Feistel轮函数，结果存储至Ri
        Feistel(Ri, SubKey[i]);
        //2.2 计算Ri
        XOR(Ri, Li, 32);
        //2.3 计算Li
        BitsCopy(Li, temp, 32);
    }
    TablePermute(plaBit, plaBit, invIP_table, 64);
    BitToHex(ciphertext, plaBit, 64);
}

void Decryption(char plaintext[8], char ciphertext[8])
{
    static bool cipherBit[64] = {0};
    static bool temp[32] = {0};
    static bool *Li = &cipherBit[0];
    static bool *Ri = &cipherBit[32];
    int i;
    //0. 明文转二进制串
    HexToBit(cipherBit, ciphertext, 64);
    //1. 初识置换IP
    TablePermute(cipherBit, cipherBit, IP_table, 64);
    //2. 16轮迭代T
    for (i = 15; i >= 0; i--)
    {
        //将Ri-1复制到temp
        BitsCopy(temp, Li, 32);
        //2.1 Feistel轮函数，结果存储至Ri
        Feistel(Li, SubKey[i]);
        //2.2 计算Ri
        XOR(Li, Ri, 32);
        //2.3 计算Li
        BitsCopy(Ri, temp, 32);
    } //
    TablePermute(cipherBit, cipherBit, invIP_table, 64);
    BitToByte(plaintext, cipherBit, 64);
}

char *EncryptionBS(char *bigSizeText, char *key){
    int len = strlen(bigSizeText);
    int size = len % 8 == 0 ? len / 8 : len / 8 + 1;
    char *enText;
    enText = (char*)malloc(size * 16 * sizeof(char));
    int i, j;
    GenerateSubKey(key);        
    for(i = 0; i < size; i++){
        char temp[8];
        for(j = 0; j < 8; j++){
            temp[j] = bigSizeText[i * 8 + j];
        }
        char *enTemp;
        enTemp = (char*)malloc(16 * sizeof(char));    
        Encryption(enTemp, temp);
        strcat(enText, enTemp);
    }
    return enText;
}

char *DecryptionBS(char *bigSizeText, char *key){
    int len = strlen(bigSizeText);
    int size = len % 16 == 0 ? len / 16 : len / 16 + 1;
    char *deText;
    deText = (char*)malloc(size * 8 * sizeof(char));
    int i, j;
    GenerateSubKey(key);        
    for(i = 0; i < size; i++){
        char temp[16];
        for(j = 0; j < 16; j++){
            temp[j] = bigSizeText[i * 16 + j];
        }
        char *deTemp;
        deTemp = (char*)malloc(8 * sizeof(char));    
        Decryption(deTemp, temp);
        strcat(deText, deTemp);        
    }
    return deText;
}